package ca.scotthyndman.as2haxe.dom;

import java.util.ArrayList;
import java.util.List;

import ca.scotthyndman.as2haxe.dom.visitor.IVisitor;

/**
 * Represents array access
 */
public class ASArrayAccess extends ASExpression {

	/**
	 * The "array" structural property of this node type.
	 */
	public static final ASChildPropertyDescriptor ARRAY_PROPERTY = new ASChildPropertyDescriptor(
			ASArrayAccess.class, "array", ASExpression.class, true);

	/**
	 * The "index" structural property of this node type.
	 */
	public static final ASChildPropertyDescriptor INDEX_PROPERTY = new ASChildPropertyDescriptor(
			ASArrayAccess.class, "index", ASExpression.class, true);

	/** The array */
	private ASExpression array;

	/** The index */
	private ASExpression index;

	/**
	 * Constructs a new instance of ASArrayAccess
	 * 
	 * @param ast
	 *            The abstract syntax tree that owns this element
	 */
	public ASArrayAccess(AST ast) {
		super(ast);
	}

	/**
	 * @param array
	 *            the array to set
	 */
	public void setArray(ASExpression array) {
		ASTNode oldChild = this.array;
		preReplaceChild(oldChild, array, ARRAY_PROPERTY);
		this.array = array;
		postReplaceChild(oldChild, array, ARRAY_PROPERTY);
	}

	/**
	 * @return the array
	 */
	public ASExpression getArray() {
		return array;
	}

	/**
	 * @param index
	 *            the index to set
	 */
	public void setIndex(ASExpression index) {
		if (index == null) {
			throw new IllegalArgumentException();
		}
		// an ArrayAccess may occur inside an Expression
		// must check cycles
		ASTNode oldChild = this.index;
		preReplaceChild(oldChild, index, INDEX_PROPERTY);
		this.index = index;
		postReplaceChild(oldChild, index, INDEX_PROPERTY);
	}

	/**
	 * @return the index
	 */
	public ASExpression getIndex() {
		return index;
	}

	// ===== INTERNAL GET/SET

	/*
	 * (omit javadoc for this method) Method declared on ASTNode.
	 */
	final ASTNode internalGetSetChildProperty(
			ASChildPropertyDescriptor property, boolean get, ASTNode child) {
		if (property == ARRAY_PROPERTY) {
			if (get) {
				return getArray();
			} else {
				setArray((ASExpression) child);
				return null;
			}
		}
		if (property == INDEX_PROPERTY) {
			if (get) {
				return getIndex();
			} else {
				setIndex((ASExpression) child);
				return null;
			}
		}
		// allow default implementation to flag the error
		return super.internalGetSetChildProperty(property, get, child);
	}

	// ===== TO STRING AND VISITOR

	/**
	 * Returns a string representation of the object.
	 */
	@Override
	public String toString() {
		return getArray().toString() + "[" + getIndex().toString() + "]";
	}

	@Override
	public void accept(IVisitor as2Visitor, boolean recursive) {
		recursive = as2Visitor.visit(this);

		if (recursive) {
			getArray().accept(as2Visitor, recursive);
			getIndex().accept(as2Visitor, recursive);
		}
	}

	// ======= STATIC CONSTRUCTION

	/**
	 * Returns a list of structural property descriptors for this node type.
	 * Clients must not modify the result.
	 * 
	 * @return a list of property descriptors (element type:
	 *         {@link ASPropertyDescriptor})
	 * 
	 */
	public static List propertyDescriptors() {
		return PROPERTY_DESCRIPTORS;
	}

	/**
	 * A list of property descriptors (element type:
	 * {@link StructuralPropertyDescriptor}), or null if uninitialized.
	 */
	private static final List<ASPropertyDescriptor> PROPERTY_DESCRIPTORS;

	static {
		List<Object> properyList = new ArrayList<Object>(3);
		createPropertyList(ASArrayAccess.class, properyList);
		addProperty(ARRAY_PROPERTY, properyList);
		addProperty(INDEX_PROPERTY, properyList);
		PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
	}
}
